<?php

namespace addons\douyin\controller;

use app\admin\model\Aivideo;
use app\common\exception\UploadException;
use app\common\library\Common;
use app\common\library\Upload;
use app\common\model\Attachment;
use Qcloud\Cos\Client;
use Qcloud\Cos\Signature;
use TencentCloud\Common\Credential;
use TencentCloud\Common\Exception\TencentCloudSDKException;
use TencentCloud\Common\Profile\ClientProfile;
use TencentCloud\Common\Profile\HttpProfile;
use TencentCloud\Vod\V20180717\Models\DeleteMediaRequest;
use TencentCloud\Vod\V20180717\VodClient;
use think\addons\Controller;
use think\Cache;
use think\Config;
use think\Log;

/**
 * COS云储存
 *
 */
class Vod extends Controller
{

    protected $cosConfig = [];


    public function _initialize()
    {
        //跨域检测
        check_cors_request();

        parent::_initialize();
        Config::set('default_return_type', 'json');

        $config = get_addon_config('cos');
        $this->cosConfig = array(
            'region'      => $config['region'],
            'schema'      => 'https', //协议头部，默认为http
            'credentials' => array(
                'secretId'  => $config['secretId'],
                'secretKey' => $config['secretKey']
            )
        );
    }

    public function index()
    {
        Config::set('default_return_type', 'html');
        $this->error("当前插件暂无前台页面");
    }

    public function params()
    {
        $this->check();

        $config = get_addon_config('cos');
        $name = $this->request->post('name');
        $md5 = $this->request->post('md5');
        $chunk = $this->request->post('chunk');

        $key = (new Upload())->getSavekey($config['savekey'], $name, $md5);
        $key = ltrim($key, "/");
        $params = [
            'key' => $key,
            'md5' => $md5
        ];
        if ($chunk) {
            $fileSize = $this->request->post('size');
            $oss = new Client($this->cosConfig);

            $result = $oss->createMultipartUpload(array(
                'Bucket' => $config['bucket'],
                'Key'    => $key,
            ));
            $uploadId = $result['UploadId'];

            $sig = new Signature($config['secretId'], $config['secretKey']);

            $partSize = $this->request->post("chunksize");
            $i = 0;
            $size_count = $fileSize;
            $values = array();
            while ($size_count > 0) {
                $size_count -= $partSize;
                $values[] = array(
                    $partSize * $i,
                    ($size_count > 0) ? $partSize : ($size_count + $partSize),
                );
                $i++;
            }

            $params['key'] = $key;
            $params['uploadId'] = $uploadId;
            $params['partsAuthorization'] = [];
            $date = gmdate('D, d M Y H:i:s \G\M\T');
            foreach ($values as $index => $part) {
                $partNumber = $index + 1;
                $options = array(
                    'Bucket'     => $config['bucket'],
                    'Key'        => $key,
                    'UploadId'   => $uploadId,
                    'PartNumber' => $partNumber,
                    'Body'       => ''
                );
                $command = $oss->getCommand('uploadPart', $options);
                $request = $oss->commandToRequestTransformer($command);
                $authorization = $sig->createAuthorization($request);

                $params['partsAuthorization'][$index] = $authorization;
            }
            $params['date'] = $date;
        } else {
            if ($config['uploadmode'] == 'client') {
                $expiretime = time() + $config['expire'];
                $expiration = gmdate("Y-m-d\TH:i:s.414\Z", $expiretime);
                $keytime = (time() - 60) . ';' . $expiretime;
                $policy = json_encode([
                    'expiration' => $expiration,
                    'conditions' => [
                        ['q-sign-algorithm' => 'sha1'],
                        ['q-ak' => $config['secretId']],
                        ['q-sign-time' => $keytime]
                    ]
                ]);
                $signature = hash_hmac('sha1', sha1($policy), hash_hmac('sha1', $keytime, $config['secretKey']));
                $params = [
                    'key'              => $key,
                    'policy'           => base64_encode($policy),
                    'q-sign-algorithm' => 'sha1',
                    'q-ak'             => $config['secretId'],
                    'q-key-time'       => $keytime,
                    'q-sign-time'      => $keytime,
                    'q-signature'      => $signature
                ];
            }
        }

        $this->success('', null, $params);
        return;
    }

    /**
     * 服务器中转上传文件
     * 上传分片
     * 合并分片
     */
    public function run($params)
    {

        $this->check();
        $config = get_addon_config('cos');
        $oss = new Client($this->cosConfig);

        $chunkid = $this->request->post("chunkid");
        if ($chunkid) {
            $action = $this->request->post("action");
            $chunkindex = $this->request->post("chunkindex/d");
            $chunkcount = $this->request->post("chunkcount/d");
            $filesize = $this->request->post("filesize");
            $filename = $this->request->post("filename");
            $method = $this->request->method(true);
            $key = $this->request->post("key");
            $uploadId = $this->request->post("uploadId");

            if ($action == 'merge') {
                //合并分片
                if ($config['uploadmode'] == 'server') {
                    $attachment = null;
                    //合并分片文件
                    try {
                        $upload = new Upload();
                        $attachment = $upload->merge($chunkid, $chunkcount, $filename);
                    } catch (UploadException $e) {
                        $this->error($e->getMessage());
                    }
                }

                $etags = $this->request->post("etags/a", []);
                if (count($etags) != $chunkcount) {
                    $this->error("分片数据错误");
                }
                $listParts = [];
                for ($i = 0; $i < $chunkcount; $i++) {
                    $listParts[] = array("PartNumber" => $i + 1, "ETag" => $etags[$i]);
                }
                try {
                    $result = $oss->completeMultipartUpload(array(
                            'Bucket'   => $config['bucket'],
                            'Key'      => $key,
                            'UploadId' => $uploadId,
                            'Parts'    => $listParts
                        )
                    );
                } catch (\Exception $e) {
                    $this->error($e->getMessage());
                }

                if (!isset($result['Key'])) {
                    $this->error("上传失败");
                } else {
                    $this->success("上传成功", '', ['url' => "/" . $key, 'fullurl' => cdnurl("/" . $key, true)]);
                }
            } else {
                //默认普通上传文件
                $file = $this->request->file('file');
                try {
                    $upload = new Upload($file);
                    $file = $upload->chunk($chunkid, $chunkindex, $chunkcount);
                } catch (UploadException $e) {
                    $this->error($e->getMessage());
                }
                try {
                    $params = array(
                        'Bucket'     => $config['bucket'],
                        'Key'        => $key,
                        'UploadId'   => $uploadId,
                        'PartNumber' => $chunkindex + 1,
                        'Body'       => $file->fread($file->getSize())
                    );
                    $ret = $oss->uploadPart($params);
                    $etag = $ret['ETag'];
                } catch (\Exception $e) {
                    $this->error($e->getMessage());
                }

                $this->success("上传成功", "", [], 3, ['ETag' => $etag]);
            }
        } else {
            $attachment = null;
            //默认普通上传文件
            $file = $this->request->file('file');
            try {
                $upload = new Upload($file);
                $attachment = $upload->upload();
            } catch (UploadException $e) {
                $this->error($e->getMessage());
            }

            //文件绝对路径
            $filePath = $upload->getFile()->getRealPath() ?: $upload->getFile()->getPathname();

            try {
                $ret = $oss->upload($config['bucket'], ltrim($attachment->url, "/"), $upload->getFile());
                //成功不做任何操作
            } catch (\Exception $e) {
                $attachment->delete();
                @unlink($filePath);
                $this->error("上传失败");
            }

            $this->success("上传成功", '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
        }
        return;
    }

    /**
     * 回调
     */
    public function notify($EventContent = [])
    {
        if(empty($EventContent))$EventContent=$this->request->post();

        if (!isset($EventContent['EventType'])) {
            Log::error(json_encode($EventContent));
        }

        $M_aivideo= new Aivideo();
        if($EventContent['EventType']=="ComposeMediaComplete")
        {

         $task_id=$EventContent['ComposeMediaCompleteEvent']['TaskId'];

         $data=[];
         if($EventContent['ComposeMediaCompleteEvent']['Status']=='FINISH')
         {

             $data['video']=$EventContent['ComposeMediaCompleteEvent']['Output']['FileUrl'];
             $data['file_id']=$EventContent['ComposeMediaCompleteEvent']['Output']['FileId'];

             if (!$data['video']) {
                 if (!empty($EventContent['ComposeMediaCompleteEvent']['Message'])) {
                     $data['exception'] = $EventContent['ComposeMediaCompleteEvent']['Message'];
                     $data['status'] = 3;
                     $M_aivideo->save($data, ['task_id' => $task_id]);
                     Log::error($EventContent['ComposeMediaCompleteEvent']['Message']);
                 }
                 return;
             }
             $data['status']=2;


             $temp_path = ROOT_PATH . 'public' . DS . 'uploads' . DS . 'txcloud';
             if (!is_dir($temp_path)) {
                 $dirres = mkdir($temp_path, 0700);
                 if (!$dirres) {
                     $this->error('无法自动创建缓存目录！请手动创建:' . $temp_path);
                 }
             }


             $rnd = substr(time(), -4);
             $file_name = date('Ymd') . $rnd . rand(0, 9) . rand(0, 9) . rand(0, 9) . '.mp4';
             $filename = request()->domain() . DS . 'uploads/txcloud/' . $file_name;
             $file_name = $temp_path . DS . $file_name;

             if (config('compose_vendor') === 'ali') {
                 $url = $data['video'];
             } else {
                 if (empty($antiStealingLinkKey = Cache::get('antiStealingLinkKey'))) {
                     $resData = json_decode(file_get_contents('http://zk.ydk1.cn/index.php/api/token/auth'), 1);
                     $antiStealingLinkKey = '';
                     if ($resData['code'] === 0) {
                         $this->error($resData['msg']);
                     } else {
                         if (empty($resData['data']['antiStealingLinkKey'])) $this->error('防盗链KEY错误');
                         $antiStealingLinkKey = $resData['data']['antiStealingLinkKey'];
                     }
                     Cache::set('antiStealingLinkKey', $antiStealingLinkKey, 3600);
                 }
                 $url = Common::getAntiStealingLink($data['video'], $antiStealingLinkKey);
             }
             file_put_contents($file_name, $this->curl_file_get_contents($url));
             $data['local']=$file_name;

         }
         else
         {
             $data['exception']=$EventContent['ComposeMediaCompleteEvent']['Message'];
             $data['status']=3;
         }
            $M_aivideo->save($data,['task_id'=>$task_id]);

        }

        if (config('compose_vendor') !== 'ali' && !empty($data['file_id'])) {
            if (!$config = Cache::get('cdk')) {
                $data_auth = json_decode(file_get_contents('http://zk.ydk1.cn/index.php/api/token/auth'), true);
                if ($data_auth['code'] == 0) {
                    Log::error(__LINE__ . $data_auth['msg']);
                }

                $config = $data_auth['data'];
                Cache::set('cdk', $config, 86400);
            }
            try {
                $cred = new Credential($config['SecretId'], $config['SecretKey']);
                $httpProfile = new HttpProfile();
                $httpProfile->setEndpoint("vod.tencentcloudapi.com");

                $clientProfile = new ClientProfile();
                $clientProfile->setHttpProfile($httpProfile);
                $client = new VodClient($cred, "", $clientProfile);
                $req = new DeleteMediaRequest();

                $params = array(
                    "FileId" => $data['file_id']
                );
                $req->fromJsonString(json_encode($params));
                $resp = $client->DeleteMedia($req);
                $resData = json_decode($json = $resp->toJsonString(), true);
                if (!isset($resData['RequestId'])) Log::error(__LINE__ . $json);
            } catch (TencentCloudSDKException $e) {
                Log::error(__LINE__ . $e->getMessage());
            }
        }

        return;
    }

    /**
     * 检查签名是否正确或过期
     */
    protected function check()
    {
        $costoken = $this->request->post('costoken', '', 'trim');
        if (!$costoken) {
            $this->error("参数不正确");
        }
        $config = get_addon_config('cos');
        list($appId, $sign, $data) = explode(':', $costoken);
        if (!$appId || !$sign || !$data) {
            $this->error("参数不正确");
        }
        if ($appId !== $config['appId']) {
            $this->error("参数不正确");
        }
        if ($sign !== base64_encode(hash_hmac('sha1', base64_decode($data), $config['secretKey'], true))) {
            $this->error("签名不正确");
        }
        $json = json_decode(base64_decode($data), true);
        if ($json['ExpireTime'] < time()) {
            $this->error("请求已经超时");
        }
    }


    protected  function  curl_file_get_contents($durl){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $durl);
        curl_setopt($ch, CURLOPT_TIMEOUT, 100);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch,CURLOPT_SSLVERSION,3);
        $r = curl_exec($ch);
        curl_close($ch);
        return $r;
    }


}
